module Sustainalytics.Authentication {
    export class AuthenticationService implements IAuthenticationService {
        private authBaseUrl: string;
        private baseUrl: string;

        constructor(
            private $q: ng.IQService,
            private $http: ng.IHttpService,
            private staticObjects: Common.IStaticObjects,
            private $location: ng.ILocationService,
            private $rootScope: any,
            private $timeout: ng.ITimeoutService,
            private $window: any) {
            var ctx = this;

            ctx.init();
            console.log("always loaded");

            //init signalr hub for logged users
            ctx.$rootScope.$watch('authData', a => {
                ctx.initSignalr();
            });
        }

        private initSignalr(): void {
            var ctx = this;
            var authToken = ctx.$rootScope['authData'] && ctx.$rootScope['authData']['access_token'] ? ctx.$rootScope['authData']['access_token'] : null;
            var userHub = $.connection['userLoginHub'];
            if (!authToken || !userHub) {
                return;
            }

            userHub['client']['notifyClient'] = a => {
                console.log(a);
                if (a === 'LOGOUT') {
                    ctx.logout();
                    ctx.$window.location.reload();
                }
                if (a === 'REFRESH') {
                    ctx.refreshToken().catch(reason => { ctx.staticObjects.redirectToLogin(); });
                }
            };

            userHub.connection.qs = { 'access_token': authToken };
            userHub.connection.url = "/accountsserv/signalr";
            userHub.connection.start();
        }

        private init(): void {
            var ctx = this;

            ctx.authBaseUrl = ctx.staticObjects.authBaseUrl;
            ctx.baseUrl = ctx.staticObjects.baseUrl;
        }

        public login(userCredentials): ng.IHttpPromise<AuthData> {
            var ctx = this;

            var promise = ctx.$http.post(ctx.authBaseUrl + "/token", userCredentials);

            return promise;
        }

        public loginWithIp(): ng.IHttpPromise<AuthData> {
            var ctx = this;
            var url = ctx.baseUrl + "/api/account/iplogin";
            return ctx.$http.post(url, "");
        }
        public logout(redirectTo?: string, err?: number, noRedirect?: boolean) {
            var ctx = this;

            localStorage.removeItem('sust_refresh_token');
            localStorage.removeItem('sust:a:ur');
            localStorage.removeItem('sust_userInfo');
            ctx.staticObjects.clearUserInfo();

            var urlParams = $.param(
                {
                    redirectTo: redirectTo ? encodeURI(redirectTo) : null,
                    err: err ? encodeURI(err.toString()) : null
                });

            if (!noRedirect)
                ctx.$location.url('/login' + (redirectTo || err ? '?' + urlParams : ''));
        }

        public profile(): ng.IHttpPromise<Common.IUserInfo> {
            var ctx = this;

            var promise = ctx.$http.post(ctx.baseUrl + "/api/account/profile", null);

            return promise;
        }

        public refreshToken(): ng.IPromise<any> {
            var ctx = this;

            var def = ctx.$q.defer();

            var refreshToken = localStorage.getItem('sust_refresh_token');

            if (refreshToken) {
                var loginParams =
                    "grant_type=refresh_token" +
                    "&refresh_token=" + refreshToken +
                    "&client_id=clientId1";

                ctx.login(loginParams)
                    .success((authData: AuthData) => {
                        if (!authData.access_token && !authData.expires_in && !authData.refresh_token) {
                            def.reject();
                        }
                        else {
                            authData.loginTime = new Date();
                            ctx.$rootScope.authData = authData;
                            localStorage.setItem('sust_refresh_token', authData.refresh_token);

                            ctx.$timeout(() => {
                                // redirect to login if the refresh token failed
                                ctx.refreshToken().catch(reason => {
                                    ctx.staticObjects.redirectToLogin();
                                });
                            }, (authData.expires_in - 5) * 1000);

                            ctx.profile()
                                .success((userInfo: Common.IUserInfo) => {
                                    ctx.$rootScope.userInfo = userInfo;
                                    def.resolve();
                                })
                                .error((userInfo: Common.IUserInfo, ...args: any[]) => {
                                    ctx.staticObjects.errorCallback.apply(ctx.staticObjects, args);
                                    def.reject();
                                });
                        }
                    })
                    .error((data, status, headers, config) => {
                        def.reject();
                    });
            }
            else {
                def.reject();
            }

            return def.promise;
        }

        public forgotPassword(username: string): ng.IHttpPromise<any> {
            var ctx = this;
            var promise = ctx.$http.post(ctx.baseUrl + "/api/account/forgotPassword", '"' + username + '"');
            return promise;
        }

        public setPassword(setPasswordParams): ng.IHttpPromise<any> {
            var ctx = this;
            var promise = ctx.$http.post(ctx.baseUrl + "/api/account/setPassword", setPasswordParams);
            return promise;
        }

        public changePassword(changePasswordParams): ng.IHttpPromise<any> {
            var ctx = this;
            var promise = ctx.$http.post(ctx.baseUrl + "/api/account/changePassword", changePasswordParams);
            return promise;
        }

        public acceptLegalAgreement(username: string): ng.IHttpPromise<any> {
            var ctx = this;
            var promise = ctx.$http.post(ctx.baseUrl + "/api/account/acceptLegalAgreement", '"' + username + '"');
            return promise;
        }

        public permissions(): ng.IHttpPromise<Sustainalytics.Claims.ActiveResourcesDto[]> {
            var ctx = this;
            var promise = ctx.$http.get("/claimsserv/api/v1/claims");

            promise
                .success((resources: Sustainalytics.Claims.ActiveResourcesDto[]) => {
                    ctx.staticObjects.resourcePermissions = angular.toJson(resources);
                    // backup
                    localStorage.setItem("sust:a:ur", angular.toJson(resources));
                });

            return promise;
        }
    }

    export var authenticationServiceName = 'AuthenticationService';

    angular.module(authenticationModuleName).service(authenticationServiceName,
        ['$q', '$http', 'staticObjects', '$location', '$rootScope', '$timeout', AuthenticationService]);
}
